package com.ajk.server.service.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ajk.server.dao.RegionDictMapper;
import com.ajk.server.model.RegionDict;
import com.ajk.server.model.query.RegionDictQuery;
import com.ajk.server.model.response.RegionDictRes;
import com.ajk.server.service.RegionDictService;
import com.ajk.server.utils.RedisKeyUtil;

/**
 * 地区  <br>
 * dict_region <br>
 * v1.0 2016-05-01
 */
 @Service
 public class RegionDictServiceImpl implements RegionDictService {
	
	private static final Logger logger = LoggerFactory.getLogger(RegionDictServiceImpl.class);
	
	@Autowired
	private RegionDictMapper regionDictMapper;
	
	@Autowired
    private RedisTemplate<String, Object> template;
	
//	List<RegionDictRes> cacheRegionDictResList = null;

//	Map<Integer, RegionDictRes> idMapRegionDictResWithChildren = new HashMap<Integer, RegionDictRes>();
//	Map<Integer, RegionDictRes> idMapRegionDictResWithNoChildren = new HashMap<Integer, RegionDictRes>();

//	public final static String REGION_TS_KEY="com.ajk.server.model.RegionDict.Ts";
//	public final static String REGION_KEY="com.ajk.server.model.RegionDict";
	
	/**
 	*根据ID删除 地区
 	*/
 	@Override
 	public Integer deleteRegionDictById(Integer id){
 		return regionDictMapper.deleteById(id);
 	}
 	
 	/**
 	*新增 地区
 	*/
 	@Override
 	@Transactional
 	public Integer batchInsertRegionDict(List<? extends RegionDict> regionDicts){
		Integer count = regionDictMapper.batchInsert(regionDicts);
		return count;
 	}
 	/**
 	*新增 地区
 	*/
 	@Override
 	@Transactional
 	public Integer insertRegionDict(RegionDict domain){
		Integer id = regionDictMapper.insert(domain);
		return id;
 	}

 	/**
 	*更新 地区
 	*/
 	@Override
 	@Transactional
 	public Integer updateRegionDict(RegionDict domain){
		Integer count = regionDictMapper.update(domain);
		return count;
 	}
 	
 	/**
 	*根据ID查询 地区
 	*/
 	public RegionDictRes findRegionDictById(Integer id){
 		String key = RedisKeyUtil.regionHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey = RedisKeyUtil.domainIdKey(id);
		RegionDictRes result = (RegionDictRes) template.opsForHash().get(key, hashKey);
 		return result;
 	}

	/**
 	*通过query 查询 地区
 	*/
	public List<RegionDict> findRegionDictByQuery(RegionDictQuery query){
		query.dealWith();
		List<RegionDict> result = regionDictMapper.findByQuery(query);
		if(CollectionUtils.isNotEmpty(result)) {
			Collections.sort(result);
			for (RegionDict regionDict : result) {
				regionDict.dealWith();
			}
		}
		return result;
	}	
	
	/**
 	*通过query count总条数
 	*/
 	public Integer countRegionDictByQuery(RegionDictQuery query){
 		query.dealWith();
 		Integer result = regionDictMapper.countByQuery(query);
 		return result;
 	}
 	
 	/**
 	* 通过ids查询
 	*/
 	public List<RegionDict> findRegionDictByIds(List<Integer> ids){
 		List<RegionDict> result = regionDictMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (RegionDict regionDict : result) {
				regionDict.dealWith();
			}
		}
		return result;
 	}
 	
 	/**
 	*根据name查询 身体部位
 	*/
	public RegionDict findByName(String name){
		RegionDict result = regionDictMapper.findByName(name);
 		if(result!=null){
 			result.dealWith();
 		}
 		return result;
	}
	
	/**
 	*获取所有字典 身体部位
 	*/
	public List<RegionDictRes> findAll(){
		List<RegionDictRes> result = regionDictMapper.findAll();
		if(CollectionUtils.isNotEmpty(result)) {
			for (RegionDict regionDict : result) {
				regionDict.dealWith();
			}
		}
		return result;
	}
	
	@Override
	public List<RegionDictRes> findAllWithCache() {
		String key = RedisKeyUtil.regionHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		List<RegionDictRes> result = new ArrayList<>();
		List<Object> list = template.opsForHash().values(key);
		if (CollectionUtils.isNotEmpty(list)) {
			for (Object object : list) {
				if(object instanceof RegionDictRes){
					result.add((RegionDictRes) object);
				}
			}
		}
		return result;
	}
	
	@Override
	public List<Integer> findSelfAllChildrenId(Integer parentId) {
		if(parentId==null){
			return null;
		}
		List<Integer> result = new ArrayList<Integer>();
		String key = RedisKeyUtil.regionHashKey();
		String parentRedisKey = RedisKeyUtil.parentIdMapRegionChildren();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		List<Object> tempResult = new ArrayList<Object>();
		if(parentId==0){
			HashOperations<String, String, RegionDictRes> hashOperations = template.opsForHash();
			List<RegionDictRes> list = hashOperations.values(key);
			if (CollectionUtils.isNotEmpty(list)) {
				for (RegionDictRes object : list) {
					if(object instanceof RegionDictRes){
						result.add(object.getId());
					}
				}
			}
			tempResult.addAll(list);
		}else if(parentId>0){
			Queue<Integer> queue = new LinkedList<Integer>();
			queue.offer(parentId);
			result.add(parentId);
			while(!queue.isEmpty()){
				Integer item = null;
				Collection<String> hashKeys = new ArrayList<String>();
				while((item=queue.poll())!=null){
					String hashKey = RedisKeyUtil.domainIdKey(item);
					hashKeys.add(hashKey);
				}
				if(CollectionUtils.isNotEmpty(hashKeys)){
					HashOperations<String, String, List<Integer>> hashOperations = template.opsForHash();
					List<List<Integer>> tempList = hashOperations.multiGet(parentRedisKey, hashKeys);
					if (CollectionUtils.isNotEmpty(tempList)) {
						for (List<Integer> children : tempList) {
							if(children instanceof List){
								if (CollectionUtils.isNotEmpty(children)) {
									for (Integer object2 : children) {
										if(object2 instanceof Integer){
											queue.offer(object2);
											result.add(object2);
										}
									}
								}
							}
						}
					}
				}
			}
		}
		return result;
	}
	
	/**
	 * 只找一层
	 */
	@Override
	public List<RegionDictRes> findByParentId(Integer parentId) {
		List<RegionDictRes> result = new ArrayList<RegionDictRes>();
		String key = RedisKeyUtil.regionHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String parentRedisKey = RedisKeyUtil.parentIdMapRegionChildren();
		String parentHashKey = RedisKeyUtil.domainIdKey(parentId);
		HashOperations<String, String, List<Integer>> hashOperations = template.opsForHash();
		List<Integer> temp = hashOperations.get(parentRedisKey, parentHashKey);
		List<String> hashKeys = new ArrayList<>();
		if(temp instanceof List){
			for(Integer id : temp){
				if(id instanceof Integer){
					String hashkey = RedisKeyUtil.domainIdKey(id);
					hashKeys.add(hashkey);
				}
			}
		}
		
		HashOperations<String, String, RegionDictRes> hashOperations2 = template.opsForHash();
		List<RegionDictRes> tempResult = hashOperations2.multiGet(key, hashKeys);
		if (CollectionUtils.isNotEmpty(tempResult)) {
			for (RegionDictRes object : tempResult) {
				if(object instanceof RegionDictRes){
					result.add(object);
				}
			}
		}
		return result;
	}
	
	@Override
	public void syncInRedis(boolean force){
		String key = RedisKeyUtil.regionHashKey();
		if(force || (!template.hasKey(key) )){
			List<RegionDictRes> result = findAll();
			Map<String, RegionDictRes> map = new HashMap<String, RegionDictRes>();
			Map<String, List<Integer>> parentMapRegion = new HashMap<String,  List<Integer>>();
			if (CollectionUtils.isNotEmpty(result)) {
				for (RegionDictRes regionDictRes : result) {
					String hashKey = RedisKeyUtil.domainIdKey(regionDictRes.getId());
					map.put(hashKey, regionDictRes);
					
					Integer parentId = regionDictRes.getParentId();
					String parentKey = RedisKeyUtil.domainIdKey(parentId);
					if(!parentMapRegion.containsKey(parentKey)){
						parentMapRegion.put(parentKey, new ArrayList<>());
					}
					parentMapRegion.get(parentKey).add(regionDictRes.getId());
				}
				if(!map.isEmpty()){
					template.delete(key);
					template.opsForHash().putAll(key, map);
//					template.expire(key, 7, TimeUnit.DAYS);
				}
				if(!parentMapRegion.isEmpty()){
					String parentRedisKey = RedisKeyUtil.parentIdMapRegionChildren();
					template.delete(parentRedisKey);
					template.opsForHash().putAll(parentRedisKey, parentMapRegion);
//					template.expire(key, 8, TimeUnit.DAYS);
				}
			}
		}
	}
	
	@Override
	public void syncSingletonRedis(Integer regionId) {
		String key = RedisKeyUtil.regionHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}else{
			RegionDict regionDict = regionDictMapper.findById(regionId);
			String hashKey = RedisKeyUtil.domainIdKey(regionId);
			if(regionDict.getInUsed()==1){
				template.opsForHash().put(key, hashKey, regionDict);
			}else{
				template.opsForHash().delete(key, hashKey);
			}
			
			
			//加载父节点对应的子儿子集合
			Integer parentId = regionDict.getParentId();
			String parentKey = RedisKeyUtil.parentIdMapRegionChildren();
			hashKey = RedisKeyUtil.domainIdKey(parentId);
			if(template.opsForHash().hasKey(parentKey, hashKey)){
				Object list = template.opsForHash().get(parentKey, hashKey);
				if(list instanceof List){
					boolean find =false;
					Object findObject = null;
					for (Object item : (List)list) {
						if(item instanceof Integer){
							if(regionId.intValue() == (Integer)item){
								find = true;
								findObject = item;
								break;
							}
						}
					}
					if(!find){
						if(regionDict.getInUsed()==1){
							((List)list).add(regionId);
							template.opsForHash().put(parentKey, hashKey,list);
						}
					}else{
						if(regionDict.getInUsed()==0){
							((List)list).remove(findObject);
							template.opsForHash().put(parentKey, hashKey,list);
						}
					}
				}
			}else if(regionDict.getInUsed()==1){
				List<Integer> list = new ArrayList<Integer>();
				list.add(regionId);
				template.opsForHash().put(parentKey, hashKey,list);
			}
			
		}
	}
	
}	